﻿using jvm.classpath;
using jvm.mm;
using jvm.native;
using jvm.rtda;
using jvm.rtda.heap;
using jvm.rtda.heap.clazz;
using jvm.rtda.heap.pool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace jvm
{
    class Jvm
    {
        public Cmd cmd;
        public JClassLoader loader;
        public JThread mainThread;
        public List<JThread> threads = new List<JThread>();

        public Jvm(Cmd cmd)
        {
            MemoryManager.Init(this);
            this.cmd = cmd;
            Classpath classpath = new Classpath();
            classpath.Parse(cmd.xJreOption, cmd.cpOption);
            loader = new JClassLoader(classpath, cmd.verboseClass);
            mainThread = new JThread();
            mainThread.sysThread = Thread.CurrentThread;
            threads.Add(mainThread);
        }

        public void Start()
        {
            InitVM();
            ExecMain();
        }

        void InitVM()
        {
            NativeMethodPool.Init();
            JClass vmClass = loader.LoadClass("sun/misc/VM");
            vmClass.Init(mainThread);
            Interpreter.Interpret(mainThread, cmd.verboseInst);
        }

        void ExecMain()
        {
            string className = cmd.clazz.Replace('.', '/');
            JClass mainClass = loader.LoadClass(className);

            JMethod mainMethod = mainClass.FindMainMethod();
            if (mainMethod == null)
            {
                Console.WriteLine("Main method not found in class {}", cmd.clazz);
                return;
            }
            JFrame frame = mainThread.NewFrame(mainMethod);
            JObject jArgs = CreateArgsArray();
            frame.localVars.SetRef(0, jArgs);
            mainThread.PushFrame(frame);
            Interpreter.Interpret(mainThread, cmd.verboseInst);
        }

        JObject CreateArgsArray()
        {
            JClass strClass = loader.LoadClass("java/lang/String");
            JObject argsArr = strClass.ArrayClass().NewArray((uint)cmd.args.Count);
            JObject[] jArgs = argsArr.Refs();
            for (int i = 0; i < jArgs.Length; i++)
            {
                jArgs[i] = StringPool.StringObject(loader, cmd.args[i]);
            }
            return argsArr;
        }
    }
}
